package sweet.toolbox.command

import java.io.{ File, FileWriter }

class CreateController(
  val toolboxProps: scala.collection.Map[String, String])
  extends ToolboxCommand{
  
  import sweet.helper.{ FileHelper, StringHelper, Regex }
  import StringHelper.string2helper // implicit string enhancer
  import FileHelper.file2helper // implicit java File enhancer
  import Regex.pattern2regex // implicit java File enhancer
  
  val summary = "Create a new controller with one or more views."
  
  val usage = """
    |Usage: toolbox create-controller <controllerName> [viewName...]
    |  Create a new controller on it's own file plus any extra views. If no view
    |  specify, default to "/index". This command will also append and register
    |  the controller in your SweetConfig file.
    """.stripMargin
          
  def exec(args: Array[String]){
    if(args.length < 1)
      throw new IllegalArgumentException("Missing project name argument.")
    val controllerName = args.take(1)(0)
    val userViewNames = args.drop(1)
    val viewNames = 
      if(!userViewNames.contains("index")) "index"::userViewNames.toList
      else userViewNames.toList
    
    val toolboxController = createToolboxController(controllerName, viewNames)
    createControllerAndViews(toolboxController)
  }
  
  def createControllerAndViews(controller: ToolboxController){
    val controllerName = controller.name
    val project = controller.project
    val destDir = new File("./")   
    val fmModel = Map("sweetProject"->project, "toolboxProps"->toolboxProps, "controller"->controller)
    
    logger.debug("Creating controller " + controllerName)
    
    // ==> Create controller class
    val controllerTemplateFile = new File(controller.controllerTemplateFilename)
    withTemplate(controllerTemplateFile){ (template, pathname) =>        
      val destFile = new File(destDir, project.controllerClassPath+"/"+controller.controllerClassName+".scala")
      if(destFile.exists) throw new Exception("Controller "+destFile.getPathname+" already exists!")
      val writer = new FileWriter(destFile)
      
      logger.info("Creating file "+destFile.getPathname)
      template.process(fmModel, writer)
    }
    logger.debug("Controller "+controllerName+" created.")
        
    // ==> Create views for this controller.
    logger.debug("Creating views ")
    val viewDir = new File(destDir, project.viewPath+"/"+controller.controllerMappingName)
    if(!viewDir.exists) viewDir.mkdirs
    val viewTemplateFile = new File(controller.viewTemplateFilename)
    withTemplate(viewTemplateFile){ (template, pathname) =>        
      for(name<-controller.viewNames){
        val destFile = new File(viewDir, name+".ftl")
        //if view exists, just skip it instead of throw exception.
        if(destFile.exists) logger.error("Skipped. View "+destFile.getPathname+" already exists!")
        
        val writer = new FileWriter(destFile)
        
        fmModel("controller").asInstanceOf[ToolboxController].viewName = name
        
        logger.info("Creating file "+destFile.getPathname)
        template.process(fmModel, writer)
      }
    }      
    logger.debug("Views created.")
    
    // ==> Update SweetConfig file for the newly added controller
    import java.io._
    logger.debug("Updating SweetConfig with controller mapping.")
    val sweetConfigDir = new File(destDir, project.sweetConfigClassPath)
    val sweetConfig = new File(sweetConfigDir, project.sweetConfigClassName+".scala")
    val sweetConfigUpdate = new File(sweetConfigDir, project.sweetConfigClassName+".scala.update")
    
    val commentKey = "toolbox.auto.update.begin"
    val updateLine = "\taddControllers(\"/"+controller.controllerMappingName+"\" -> new "+controller.controllerClassName+")"
    
    val pwriter = new PrintWriter(new FileWriter(sweetConfigUpdate))
    var updated = false
    sweetConfig.eachLine{ ln=>
      pwriter.println(ln)
      if(!updated && ln.contains("toolbox.auto.update.begin")){
         pwriter.println(updateLine)
         updated = true
      } 
    }
    pwriter.flush()
    pwriter.close()
    
    if(updated){      
      //keep one rotation of backup.
      val sweetConfigBackup = new File(sweetConfigDir, project.sweetConfigClassName+".scala.backup")
      if(sweetConfigBackup.exists) sweetConfigBackup.delete
      sweetConfig.renameTo(sweetConfigBackup)
      sweetConfigUpdate.renameTo(sweetConfig)
      logger.info("SweetConfig updated. ")
    }else{
      logger.info("SweetConfig FAILED to update because comment key "+ commentKey + " can't be found.")
      sweetConfigUpdate.delete()
    }
  }
  
  def createToolboxController(controllerName: String, viewNames: List[String])={
    val p = toolboxProps
    val project = new ToolboxProject
    project.loadFrom(new File(toolboxProjectFilename))
    val tc = new ToolboxController
    tc.project = project
    tc.name = controllerName
    tc.viewNames = viewNames
    tc.controllerClassName = NamesHelper.camelCaseName(controllerName)+"Controller"
    tc.controllerMappingName = controllerName.toLowerCase
    tc.controllerTemplateFilename = p("sweet.toolbox.home")+p("toolbox.templates.dir")+"/create-controller/controller.ftl"
    tc.viewTemplateFilename = p("sweet.toolbox.home")+p("toolbox.templates.dir")+"/create-controller/view.ftl"
    tc
  }
}

class ToolboxController extends FilePropsModel{
  var project: ToolboxProject = _
  var name: String = _
  var viewNames: List[String] = _
  var controllerMappingName: String = _  
  var controllerClassName: String = _
  var controllerTemplateFilename: String = _
  var viewTemplateFilename: String = _
  var viewName: String = _
}

